#include "StdAfx.h"
#include ".\texture.h"


/************************************************************************/
/* static variable														*/
/* initialize with the first call to GetInstance						*/
/************************************************************************/
TextureManager* TextureManager::_pinstancesingleton=NULL;
//TextureManager* pTextureManager;


/************************************************************************/
/* helper routines														*/
/************************************************************************/


bool InitTextureManager(GLenum wrap/*=GL_CLAMP*/,TextureFilter filter/*=TF_linear*/)
{
	glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
	glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,wrap);
	glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,wrap);

	glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
	switch(filter) 
	{
	case TF_nearest:
		glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
		glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST);
		break;
	case TF_linear:
		glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
		break;
	case TF_bilinear:
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
		break;
	case TF_trilinear:
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
		break;

	default:
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
		break;
	}

	/*pTextureManager=TextureManager::pinstance();
	if(pTextureManager==NULL)
		return false;*/
	return true;
}

//////////////////////////////////////////////////////////////////////////
bool DeinitTextureManager()
{
/*	if(pTextureManager)
	{
		pTextureManager->deleteSingleton();
		return true;
	}*/
	TextureManager::deleteSingleton();
	return false;
}

//////////////////////////////////////////////////////////////////////////
GLuint LoadTexture(const char* name)
{
	GLuint id;
	id = TextureManager::pinstance()->LoadTexture(name);
	return id;
}

//////////////////////////////////////////////////////////////////////////
GLuint	LoadFont(char* name)
{
	GLuint id;
	id = TextureManager::pinstance()->LoadFont(name);
	return id;
}

//////////////////////////////////////////////////////////////////////////
bool DeleteTexture(const char* name)
{
	//return pTextureManager->DeleteTexture(name);
	return TextureManager::pinstance()->DeleteTexture(name);
}

//////////////////////////////////////////////////////////////////////////
bool DeleteTexture(GLuint id)
{
	if(glIsTexture(id))
	{
		glDeleteTextures(1,&id);
		return true;
	}
	return false;
}
/************************************************************************/
/*	if the static pInstanceSingleton is not yet initialized, do it		*/
/*	then return it														*/
/*	this way there can be only one instance of this class in the app	*/	
/************************************************************************/
/*TextureManager* TextureManager::GetInstance()
{
	
}*/

TextureManager::TextureManager(void)
{
	//init the container
	_textures.clear();

	//check if the shared lib's version matches the executable's version.
	if (ilGetInteger(IL_VERSION_NUM) < IL_VERSION ||
		ilGetInteger(ILU_VERSION_NUM) < ILU_VERSION ||
		ilGetInteger(ILUT_VERSION_NUM) < ILUT_VERSION) 
	{
		Log("Got problem with DevIL lib versions.... ");
	}
	ilInit();						// Needed to initialize DevIL.	
	ilEnable(IL_CONV_PAL);			// GL cannot use palettes anyway, so convert early.	
	ilutEnable(ILUT_OPENGL_CONV);	// Gets rid of dithering on some nVidia-based cards.	
	ilutRenderer(ILUT_OPENGL);		// Lets ILUT know to use its OpenGL functions.
}

TextureManager::~TextureManager(void)
{
	DeleteAllTextures();
}

/************************************************************************/
/* empty the texture container and free the textures					*/
/************************************************************************/
void TextureManager::DeleteAllTextures()
{
	//if no textures stored, leave us alone....
	if(_textures.empty())
		return;

	//iterate through the container and
	//delete textures one by one
	TextureMap::iterator tmI;
	for(tmI= _textures.begin(); tmI!=_textures.end(); tmI++)
	{
		glDeleteTextures(1,&(*tmI).second);	
	}
	//then clear the container
	_textures.clear();
}

/************************************************************************/
/*	loads an image from the disk and makes a texture from it			*/
/*	returns the opengl texture id										*/
/*	if the image has been previously load, returns the previous id		*/
/*		avoiding duplicates in memory									*/
/************************************************************************/
GLuint TextureManager::LoadTexture(const char* name)
{
	GLuint TexID = 0;	// GL texture ID
	ILuint ImgId = 0;	// IL image ID
	
	//if filename is empty don't even try...
	if(name==NULL)
		return 0;

	/*
	 	if there's already a texture with this name
		its probably the same texture. Anyway don't load it again
		return the previous one...
	 */
	if( _textures.find( name )!=_textures.end() )
		return _textures[ name ];


	// Generate the main image name to use.
	ilGenImages(1, &ImgId);
	// Bind this image name.
	ilBindImage(ImgId);

	// Loads the image specified by filename into the ImgId image.
	char fn[256];
	strcpy(fn,name);
	if (!ilLoadImage(fn))
	{
		Log("TextureManager::LoadTexture: no image %s found",name);
		return 0;
	}
	//for some reason, il shows the images upside-down
	//so flip it from the beginning to show them correctly
	iluFlipImage();

	TexID = ilutGLBindMipmaps();
	if(TexID!=0)
		_textures[name] = TexID;

	// We're done with our image, so we go ahead and delete it.
	ilDeleteImages(1, &ImgId);
	return TexID;
}

/************************************************************************/
/*                                                                      */
/************************************************************************/
GLuint TextureManager::LoadFont(char* name)
{
	GLuint TexID = 0;	// GL texture ID
	ILuint ImgId = 0;	// IL image ID

	//if filename is empty don't even try...
	if(name==NULL)
		return 0;

	/*
	if there's already a texture with this name
	its probably the same texture. Anyway don't load it again
	return the previous one...
	*/
	if( _textures.find( name )!=_textures.end() )
		return _textures[ name ];

	ilGenImages(1, &ImgId);		// Generate the main image name to use.
	ilBindImage(ImgId);			// Bind this image name.
	
	// Loads the image specified by filename into the ImgId image.
	if (!ilLoadImage(name))
	{
		Log("TextureManager::LoadFont(): no image %s found\n",name);
		return 0;
	}
	

	int width = ilGetInteger(IL_IMAGE_WIDTH);
	int height = ilGetInteger(IL_IMAGE_HEIGHT);

	glGenTextures(1, &TexID);
	glBindTexture (GL_TEXTURE_2D, TexID);
	glPixelStorei(GL_UNPACK_ALIGNMENT,1);
	glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
	glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
	glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
	glTexImage2D (GL_TEXTURE_2D, 0, GL_ALPHA8, width, height, 0, GL_ALPHA, GL_UNSIGNED_BYTE, ilGetData());

	if(TexID!=0)
		_textures[name] = TexID;

	// We're done with our image, so we go ahead and delete it.
	ilDeleteImages(1, &ImgId);
	return TexID;
}


/************************************************************************/
/*	find the id of the texture and if exists, bind it					*/
/*	do also error checking												*/
/************************************************************************/
GLuint TextureManager::BindTexture(const char* name)
{
	GLuint id = GetTexture(name);
	if(id<1)
		return 0;
	
	//just make sure that the container contains 
	//legitimate texture ids
	ASSERT(glIsTexture(id));

	glBindTexture(GL_TEXTURE_2D,id);
	return id;
}

/************************************************************************/
/* remove the specified texture from memory and its id from the			*/
/* container                                                            */
/************************************************************************/
bool TextureManager::DeleteTexture(const char* name)
{
	GLuint id = GetTexture(name);
	if(id<1)	//no such texture, beat it!
		return false;
	
	ASSERT(glIsTexture(id));

	//delete texture from card memory
	glDeleteTextures(1,&id);
	//delete id from container
	_textures.erase(name);
	return true;
}


string TextureManager::GetName( GLuint id )
{	
	TextureMap::iterator iter = _textures.begin();
	while ( iter!=_textures.end())
	{
		if( (*iter).second == id )
			return  (*iter).first;
		++iter;
	}
	
	return "";
}




#ifdef _DEBUG

/*
 	print all texture names and associated ids
 */
void TextureManager::DumpTextures()
{
	Log( "---------------------------------------" );
	Log( "Texture manager has %d textures: ",(int)_textures.size() );
	TextureMap::iterator iter = _textures.begin();
	while ( iter!=_textures.end() )
	{
		Log( "> name: %s, id: %d",iter->first.c_str(),iter->second );
		++iter;
	}
	Log( "End dumping textures" );
	Log( "---------------------------------------" );
}

/*
	trace all texture names and associated ids
*/
void TextureManager::TraceTextures()
{
	TRACE0( "---------------------------------------\n" );
	TRACE1( "Texture manager has %d textures: \n",(int)_textures.size() );
	TextureMap::iterator iter = _textures.begin();
	while ( iter!=_textures.end() )
	{
		TRACE2( "> name: %s, id: %d\n",iter->first.c_str(),iter->second );
		++iter;
	}
	TRACE0( "End dumping textures\n" );
	TRACE0( "---------------------------------------\n" );
}

#endif

/************************************************************************
	return the id of a specified textured if it is loaded
	else return 0

************************************************************************/
GLuint TextureManager::GetTexture(const char* name)
{ 
	if( _textures.find( name )!=_textures.end() )
		return _textures[name]; 
	return 0;
}





